# pytombo - Python library for processing plain text + encrypted notes.
# Copyright (C) 2007  Chris Clark

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import errno

import pytombo.search
import pytombo.tombonote


class PyTomboException(Exception):
    '''Base PyTombo exception'''
    
class PyTomboIO(PyTomboException):
    '''PyTombo I/O exception'''


class BaseNotes(object):
    
    SearchCancelled = pytombo.search.SearchCancelled
    __name__ = 'BaseNotes'
    
    def __init__(self, note_root):
        self.note_root = note_root
    
    def recurse_notes(self, sub_dir=None, filename_filter=pytombo.search.note_filename_filter_gen()):
        raise NotImplementedError('Implement in sub-class')
    
    def directory_contents(self, dirname=None):
        """Simple non-recursive Tombo note lister.
        Returns tuple (list of directories, list of files) in @dirname"""
        raise NotImplementedError('Implement in sub-class')
    
    def search_iter(self, *args, **kwargs):
        """Same API as search_iter()"""
        raise NotImplementedError('Implement in sub-class')
    
    def note_contents(self, filename, password=None, dos_newlines=True):
        """password is either plaintext (bytes) password or a password func
        """
        raise NotImplementedError('Implement in sub-class')

    def note_contents_save(self, notetext, orig_notetext=None, filename=None, password=None, dos_newlines=True, backup=True):
        raise NotImplementedError('Implement in sub-class')
    
    def note_delete(self, filename, backup=True):
        pass

    def note_size(self, filename):
        return 9999999999  # more likely to be noticed as an anomaly
        return -1

class FileNotes(BaseNotes):
    """PyTombo notes on local file system, just like original Windows Tombo
    """
    def recurse_notes(self, sub_dir=None, filename_filter=pytombo.search.note_filename_filter_gen()):
        notedir = self.note_root
        if sub_dir:
            notedir = os.path.join(self.note_root, sub_dir)
        for filename in pytombo.search.recurse_notes(notedir, filename_filter):
            yield pytombo.tombonote.remove_leading_path(notedir, filename)

    def directory_contents(self, dirname=None):
        """Simple non-recursive Tombo note lister.
        Returns tuple (list of directories, list of files) in @dirname"""
        if not dirname:
            dirname = self.note_root
        else:
            dirname = os.path.join(self.note_root, dirname)
        
        return pytombo.search.directory_contents(dirname)
    
    def search_iter(self, search_term, search_path, search_term_is_a_regex=True, ignore_case=True, search_encrypted=False, get_password_callback=None, progess_callback=None, findonly_filename=None, index_name=None):
        """Search for `search_term`, returning a generator of:
            tuple of (note_filename, [list of matches, tuple of (line_number, whole_line])
            Example:
                ['somefile.txt', [(2, 'line two'),]]
        
        Two types of "grep" (i.e. not full text search) supported:

            1)  direct search for this phrase
            2)  regex search
        
        NOTE search_path is IGNORED
        index_name - is here only for api compatibility (with full text search). It could be ignored if provided but this is probably a mistake by the caller so raise a warning
        """

        search_path = self.note_root
        temp_iter = pytombo.search.search_iter(search_term, search_path, search_term_is_a_regex=search_term_is_a_regex, ignore_case=ignore_case, search_encrypted=search_encrypted, get_password_callback=get_password_callback, progess_callback=progess_callback, findonly_filename=findonly_filename, index_name=index_name)
        for filename, hit_info in temp_iter:
            yield (pytombo.tombonote.remove_leading_path(search_path, filename), hit_info)

    def note_contents(self, filename, password=None, dos_newlines=True):
        try:
            fullpath_filename = os.path.join(self.note_root, filename)
            return pytombo.tombonote.file_contents(fullpath_filename, get_pass=password, dos_newlines=dos_newlines)
        except IOError, info:
            if info.errno == errno.ENOENT:
                raise PyTomboIO('Error opening %r file/directory does not exist' % filename)
            else:
                raise

    def note_contents_save(self, notetext, orig_notetext=None, filename=None, password=None, dos_newlines=True, backup=True):
        fullpath_filename = os.path.join(self.note_root, filename)
        # TODO need mkdir either here or in pytombo.tombonote.save_file_contents
        return pytombo.tombonote.save_file_contents(notetext, orig_notetext=orig_notetext, filename=fullpath_filename, get_pass=password, dos_newlines=dos_newlines, backup=backup)

    def note_delete(self, filename, backup=True):
        fullpath_filename = os.path.join(self.note_root, filename)
        if os.path.exists(fullpath_filename):
            if backup:
                os.rename(fullpath_filename, fullpath_filename + '.bak')
            else:
                os.unlink(fullpath_filename)

    def note_size(self, filename):
        try:
            fullpath_filename = os.path.join(self.note_root, filename)
            return os.path.getsize(fullpath_filename)
        except IOError, info:
            if info.errno == errno.ENOENT:
                raise PyTomboIO('Error opening %r file/directory does not exist' % filename)
            else:
                raise
        except WindowsError, info:
            if info.errno == errno.ENOENT:
                raise PyTomboIO('Error opening %r file/directory does not exist' % filename)
            else:
                raise

